package oceanserv

import (
	"codedef"
	"github.com/golang/protobuf/proto"
	"github.com/gorilla/websocket"
	"log"
	"ocean"
	"rhelper"
)

type Gateway struct {
	gwId        string
	ws          *websocket.Conn
	chanx       chan bool
	controllers map[int32]*Controller
}

func newGateway(gwId string, ws *websocket.Conn) *Gateway {
	g := &Gateway{}
	g.gwId = gwId
	g.ws = ws
	g.chanx = make(chan bool, 1)
	g.controllers = make(map[int32]*Controller)

	return g
}

func (g *Gateway) onKeepAlive() {
	log.Printf("gateway %s got a keep alive message\n", g.gwId)
}

func (g *Gateway) onGatewayMessage(tunnel *ocean.Tunnel) {
	switch tunnel.GetCmd() {
	case codedef.CmdGatewayKeepAlive:
		g.onKeepAlive()
		break
	case codedef.CmdGatewayControllerOn:
		g.onControllerOn(tunnel)
		break
	case codedef.CmdGatewayControllerOff:
		g.onControllerOff(tunnel)
		break
	}
}

func (g *Gateway) onControllerOn(tunnel *ocean.Tunnel) {
	reg := &ocean.CGControllerReg{}
	err := proto.Unmarshal(tunnel.GetData(), reg)

	if err != nil {
		log.Println("onControllerOn error: ", err)
		return
	}

	c, ok := g.controllers[reg.GetId()]
	if !ok {
		c = &Controller{}
		c.gwId = g.gwId
		c.id = reg.GetId()
		g.controllers[c.id] = c
	}

	c.ctype = reg.GetType()
	c.apptype = reg.GetApptype()

	c.save2DB()

	log.Println("controller on, id:", reg.GetId())
}

func (g *Gateway) onControllerOff(tunnel *ocean.Tunnel) {
	leave := &ocean.GSControllerLeave{}

	err := proto.Unmarshal(tunnel.GetData(), leave)
	if err != nil {
		log.Println("onControllerOff error: ", err)
		return
	}

	c, ok := g.controllers[leave.GetId()]
	if !ok {
		log.Println("onControllerOff failed, no controller with id:", leave.GetId())
		return
	}

	delete(g.controllers, leave.GetId())
	c.onLeave()

	log.Println("controller off, id:", leave.GetId())
}

func (g *Gateway) onConnectionBreak() {
	for _, v := range g.controllers {
		v.onConnectionBreak()
	}
}

func (g *Gateway) onControllerMessage(tunnel *ocean.Tunnel) {
	controllerId := tunnel.GetTarget()
	c, ok := g.controllers[controllerId]
	if !ok {
		log.Println("onControllerMessage failed, no such controller:", controllerId)
		return
	}

	c.onMessage(tunnel)
}

func (g *Gateway) save2DB() {
	conn := rhelper.Pool().Get()
	defer conn.Close()

	_, err := conn.Do("HSET", rhelper.GatewayHash+g.gwId, "id", g.gwId)
	if err != nil {
		log.Println("gateway save2DB failed:", err)
	}
}
